package org.jkuang.qstar.commons.db;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;
import javax.sql.rowset.CachedRowSet;

import com.mchange.v2.c3p0.DataSources;
import com.sun.rowset.CachedRowSetImpl;

/**
 * 
 * @author jkuang
 * 
 */
public class ConnFactory {
	private static DBEntry defaultConfig = null;
	private static Map<String, DBEntry> datapools = new HashMap<String, DBEntry>();

	public static void addDBSource(String defaultSource, Map<String, String> source)
			throws SQLException, FileNotFoundException {
		if (defaultConfig == null) {
			defaultConfig = toDBEntry(toProperties(defaultSource));
		}
		Iterator<Map.Entry<String, String>> iterator = source.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<String, String> entry = iterator.next();
			if (!datapools.containsKey(entry.getKey())) {
				datapools.put(entry.getKey(), toDBEntry(toProperties(entry.getValue())));
			}
		}
	}

	static Properties toProperties(String filePath) throws FileNotFoundException {
		Properties config = new Properties();
		InputStream in = new BufferedInputStream(new FileInputStream(filePath));
		config = new Properties();
		try {
			config.load(in);
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return config;
	}

	static DBEntry toDBEntry(Properties config) throws SQLException {
		String username = config.getProperty("username"); // GetProperties.readValue("username_local");
		String password = config.getProperty("password");// GetProperties.readValue("password_local");
		String jdbcUrl = config.getProperty("jdbcUrl");
		String driverClass = config.getProperty("driverClass");
		if (driverClass.toLowerCase().indexOf("mysql") > 0) {
			return new DBEntry(new DataPool(jdbcUrl, driverClass, username, password), DBType.MYSQL);
		} else if (driverClass.toLowerCase().indexOf("oracle") > 0) {
			return new DBEntry(new DataPool(jdbcUrl, driverClass, username, password), DBType.ORACLE);
		} else if (driverClass.toLowerCase().indexOf("sqlserver") > 0) {
			return new DBEntry(new DataPool(jdbcUrl, driverClass, username, password), DBType.SQLSERVER);
		} else {
			System.err.println("not support driverClass:" + driverClass);
			throw new SQLException("not support driverClass:" + driverClass);
		}

	}

	static class DBEntry {
		DataPool dataPool;
		DBType dbType;

		public DBEntry(DataPool dataPool, DBType dbType) {
			this.dataPool = dataPool;
			this.dbType = dbType;
		}

	}

	public static Connection getConnection(String propertyeName) throws SQLException {
		if (datapools.containsKey(propertyeName)) {
			return datapools.get(propertyeName).dataPool.getConnection();
		} else {
			return defaultConfig.dataPool.getConnection();
		}
	}

	public static DBType getDBType(String propertyeName) throws SQLException {
		if (datapools.containsKey(propertyeName)) {
			return datapools.get(propertyeName).dbType;
		} else {
			return defaultConfig.dbType;
		}
	}

	static final class DataPool {

		private final DataSource pooled;
		static final int rows = 1000;
		static final int retry = 3;

		public DataPool(String jdbcUrl, String driverClass, String user, String password) throws SQLException {
			this.pooled = getDataSource(jdbcUrl, driverClass, user, password);
		}

		public DataPool(String jdbcUrl, Properties driverProps) {
			this.pooled = getDataSource(jdbcUrl, driverProps);
		}

		public boolean isEmpty(String value) {
			return value == null || value.equals("");
		}

		public Connection getConnection() throws SQLException {
			Connection conn = pooled.getConnection();
			conn.setAutoCommit(true);
			return conn;
		}

		public DataSource getDataSource(String jdbcUrl, String driverClass, String user, String password) {
			Properties driverProps = new Properties();
			driverProps.setProperty("user", user);
			driverProps.setProperty("username", user);
			driverProps.setProperty("password", password);
			driverProps.setProperty("driverClass", driverClass);
			try {
				Class.forName(driverClass);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(jdbcUrl);

			return getDataSource(jdbcUrl, driverProps);
		}

		public static DataSource getDataSource(String jdbcUrl, Properties driverProps) {
			try {
				DataSource unpooled = DataSources.unpooledDataSource(jdbcUrl, driverProps);
				return DataSources.pooledDataSource(unpooled);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}

		public static void destroy(DataSource dataSource) {
			try {
				if (dataSource != null) {
					DataSources.destroy(dataSource);
					dataSource = null;
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		public void destroy() {
			try {
				destroy(pooled);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	public static void close(ResultSet o) {
		try {
			if (o != null)
				o.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void close(Statement o) {
		try {
			if (o != null)
				o.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void close(Connection o) {
		try {
			if (o != null)
				o.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static CachedRowSet getCachedRowSet(String sql) throws SQLException {
		CachedRowSetImpl impl = new CachedRowSetImpl();
		impl.setCommand(sql);
		return impl;

	}

	public static enum DBType {

		MYSQL, ORACLE, SQLSERVER;
	}

	/*
	 * public static void main(String[] args) throws SQLException,
	 * FileNotFoundException { addDBSource(
	 * "D:\\devtool\\workspace\\spring-boot-indexbuilder\\etc\\mysql.properties",
	 * new HashMap<String,String>()); Connection connection=getConnection("");
	 * System.out.println("Okk-----------------------------"); }
	 */
}
